package com.kun.framework.data.persistence;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import com.kun.framework.core.exception.Assert;
import com.kun.framework.core.util.JacksonUtil;
import com.kun.framework.data.persistence.enums.PersistenceFileTypeEnum;
import com.kun.framework.data.persistence.rule.FileCreateRule;

import java.io.File;
import java.nio.charset.StandardCharsets;

/**
 * 坤坤默认数据持久化抽象类。
 * 职责：
 * 1.将数据写入磁盘，返回{@link File}对象
 * 2.将数据从磁盘读取出来，返回文件内的字符串
 * 3.将文件内的字符串转换成对象
 *
 * @author gzc
 * @since 2024/8/21
 **/
public abstract class DefaultAbstractDataPersistence<D> implements DataPersistence<D> {
    /**
     * 存储文件基础目录
     */
    protected final String baseStorageDir;
    protected final FileCreateRule fileCreateRule;
    protected final PersistenceFileTypeEnum fileTypeEnum;

    public DefaultAbstractDataPersistence(String baseStorageDir,
                                          FileCreateRule fileCreateRule,
                                          PersistenceFileTypeEnum fileTypeEnum) {
        this.baseStorageDir = baseStorageDir;
        this.fileCreateRule = fileCreateRule;
        this.fileTypeEnum = fileTypeEnum;
    }


    @Override
    public String dataReadFromDisk() {
        String inputFilePath = fileCreateRule.getInputFilePath(baseStorageDir, fileTypeEnum);
        Assert.notBlank(inputFilePath, "文件路径为空");
        return FileUtil.exist(inputFilePath)
                ? FileUtil.readString(inputFilePath, StandardCharsets.UTF_8)
                : "";
    }

    @SuppressWarnings("ALL")
    @Override
    public D dataStrConvertObj(String dataStr) {
        D data = null;
        JsonNode jsonNode = JacksonUtil.parseJsonObj(dataStr);
        if (jsonNode != null) {
            TypeReference<D> reference = new TypeReference<>() {
            };
            if (JsonNodeType.ARRAY == jsonNode.getNodeType()) {
                data = JacksonUtil.parseArray(dataStr, reference);
            } else if (JsonNodeType.OBJECT == jsonNode.getNodeType() || JsonNodeType.POJO == jsonNode.getNodeType()) {
                data = JacksonUtil.parseObject(dataStr, reference);
            } else if (JsonNodeType.BOOLEAN == jsonNode.getNodeType()) {
                data = (D) Boolean.valueOf(dataStr);
            } else if (JsonNodeType.NUMBER == jsonNode.getNodeType()) {
                data = (D) Double.valueOf(dataStr);
            } else if (JsonNodeType.BOOLEAN == jsonNode.getNodeType()) {
                data = (D) Boolean.valueOf(dataStr);
            } else {
                data = (D) dataStr;
            }
        }
        return data;
    }

    @Override
    public File dataWriteToDisk(String dataStr) {
        String outputFilePath = fileCreateRule.getOutputFilePath(baseStorageDir, fileTypeEnum);
        File file;
        if (StrUtil.isBlank(dataStr)) {
            return FileUtil.file(outputFilePath);
        }
        if (FileUtil.exist(outputFilePath)) {
            if (!fileCreateRule.isOverride()) {
                // 文件存在，且不重写文件则直接在原文件内容下添加数据
                file = FileUtil.appendString(dataStr, outputFilePath, StandardCharsets.UTF_8);
            } else {
                // 文件存在，且重写文件，则直接替换原文件
                file = FileUtil.writeString(dataStr, outputFilePath, StandardCharsets.UTF_8);
            }
        } else {
            // 文件不存在，则直接创建文件
            file = FileUtil.writeString(dataStr, FileUtil.touch(outputFilePath), StandardCharsets.UTF_8);
        }
        return file;
    }

    @Override
    public File flushDataWriteToDisk() {
        String dataStr = "";
        Object data = getDataObj();
        if (data != null) {
            if (PersistenceFileTypeEnum.JSON == fileTypeEnum) {
                dataStr = JacksonUtil.toJsonStr(data);
            } else if (PersistenceFileTypeEnum.TXT == fileTypeEnum) {
                dataStr = data.toString();
            }
        }
        return dataWriteToDisk(dataStr);
    }

}

